from abc import ABC, abstractmethod
from pathlib import Path
from queue import Queue
from typing import ClassVar, Dict, Type, List, Union, Optional

from config import COMPRESS
from implement.gather.dir_gather import DirectoryGather
from implement.gather.file_gather import FileGather
from interface.gather_interfaces import GatherInterfaces
from utils.LogDecorator import LogDecorator

log = LogDecorator(name=__name__)


class PathToolFactory(ABC):

    @abstractmethod
    def create_path(self, queue: Queue, path: Optional[Union[Path, str]] = None,
                    types: set = COMPRESS) -> GatherInterfaces:
        """创建收集器器实例"""
        pass

    @classmethod
    @abstractmethod
    def is_available(cls, name: str) -> bool:
        """检查工具是否可用"""
        pass


class PathToolFactoryRegistry:
    """工厂注册中心（单例模式）"""
    _instance: ClassVar = None
    _factories: Dict[str, Type[PathToolFactory]] = {}

    def __new__(cls):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
            cls._initialize_default_factories()
        return cls._instance

    @classmethod
    def _initialize_default_factories(cls):
        """初始化默认工厂"""
        cls.register_factory('DirectoryGather', DirGatherFactory)
        cls.register_factory('FileGather', FileFactory)

    @classmethod
    def register_factory(cls, name: str, factory: Type[PathToolFactory]):
        """注册新的工厂类型"""
        if not issubclass(factory, PathToolFactory):
            raise TypeError("Factory must be a subclass of CompressionToolFactory")
        cls._factories[name.lower()] = factory

    @classmethod
    def unregister_factory(cls, name: str):
        """取消注册工厂类型"""
        cls._factories.pop(name.lower(), None)

    @classmethod
    def get_available_factories(cls) -> List[Type[PathToolFactory]]:
        """获取所有已注册的工厂类型"""
        return list(cls._factories.values())


class DirGatherFactory(PathToolFactory):
    @classmethod
    def is_available(cls, name: str) -> bool:
        return name == 'DirectoryGather'

    def create_path(self, queue: Queue, path: Optional[Union[Path, str]] = None,
                    types: set = COMPRESS) -> GatherInterfaces:
        return DirectoryGather(queue, path, types)


class FileFactory(PathToolFactory):
    @classmethod
    def is_available(cls, name: str) -> bool:
        return name == 'FileGather'

    def create_path(self, queue: Queue, path: Optional[Union[Path, str]] = None,
                    types: set = COMPRESS) -> GatherInterfaces:
        return FileGather(queue, path, types)


class PathToolFactorySelector:
    """工厂选择器（策略模式）"""

    @classmethod
    def select_factory(cls, name: str) -> PathToolFactory:
        registry = PathToolFactoryRegistry()
        for factory in registry.get_available_factories():
            if factory.is_available(name):
                return factory()


class JudgementPath:
    """工具可用性判断器"""

    def __init__(self, name: str):
        self._factory = PathToolFactorySelector.select_factory(name)

    def get_path(self, queue: Queue, path: Optional[Union[Path, str]] = None,
                 types: set = COMPRESS) -> GatherInterfaces:
        """获取压缩器实例"""
        return self._factory.create_path(queue, path, types)

    def __str__(self):
        return f"{self.__class__.__name__} [Using: {type(self._factory).__name__}]"


if __name__ == '__main__':
    paths = JudgementPath("DirectoryGather")
    file = paths.get_path(queue=Queue(), path=r"E:\myproject\python\extract-script\log\unzip.7z")
    print(file)
